Das erste wirklich AI-native Betriebssystem
Mistral lokal auf deinem Gerät, vollständige RAG-Pipeline, CRUD-Operations als native OS-Skills. Keine Cloud. Keine API-Limits. Nur pure, lokale AI-Power.
Nicht "ein OS mit AI-Features", sondern ein OS, dessen Betriebssystem-Logik selbst AI ist. Das LLM ist nicht eine App – das LLM IST das Betriebssystem.
"Zeig mir alle PDFs über Finanzen aus letztem Monat"
Intent → Execution Plan → System Calls
Vector DB + Embeddings + Context Retrieval
Create | Read | Update | Delete Operations
OPFS + IndexedDB + Browser APIs
Ollama ist der einfachste Weg, um LLMs lokal zu betreiben.
# Linux Installation
curl -fsSL https://ollama.com/install.sh | sh
# Model downloaden (Mistral 7B)
ollama pull mistral
# Server starten
ollama serve
# Test
ollama run mistral "Hello, wie gehts?"
# Virtual Environment erstellen
python3 -m venv ai-os-env
source ai-os-env/bin/activate
# Dependencies installieren
pip install fastapi uvicorn langchain ollama chromadb sentence-transformers
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from langchain.llms import Ollama
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
import json
app = FastAPI()
# CORS für Frontend
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Ollama LLM initialisieren
llm = Ollama(
model="mistral",
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
)
@app.websocket("/ws/chat")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
# User Message empfangen
data = await websocket.receive_text()
message = json.loads(data)
# LLM Response generieren
response = llm(message["prompt"])
# Response zurücksenden
await websocket.send_json({
"type": "response",
"content": response
})
@app.post("/api/chat")
async def chat(request: dict):
"""REST API Endpoint"""
prompt = request.get("prompt", "")
response = llm(prompt)
return {
"response": response,
"model": "mistral-7b"
}
# Server starten
# uvicorn main:app --host 0.0.0.0 --port 8000
// AI Service im Browser
class LocalAI {
constructor() {
this.ws = null;
this.connect();
}
connect() {
this.ws = new WebSocket('ws://localhost:8000/ws/chat');
this.ws.onopen = () => {
console.log('🤖 AI Connected');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleResponse(data);
};
}
async ask(prompt, context = {}) {
// Message an LLM senden
this.ws.send(JSON.stringify({
prompt: prompt,
context: context,
timestamp: Date.now()
}));
}
handleResponse(data) {
// Response verarbeiten
const event = new CustomEvent('ai-response', {
detail: data
});
window.dispatchEvent(event);
}
}
// Initialisieren
const ai = new LocalAI();
// Verwenden
ai.ask("Liste alle Dateien im /documents Ordner");
// Response lauschen
window.addEventListener('ai-response', (e) => {
console.log('AI:', e.detail.content);
});
| Model | Größe | RAM | Performance | Use Case |
|---|---|---|---|---|
| TinyLlama | 637 MB | 2 GB | ⭐⭐ | Embedded Devices |
| Phi-2 | 1.7 GB | 4 GB | ⭐⭐⭐ | Mini PCs |
| Mistral 7B | 4.1 GB | 8 GB | ⭐⭐⭐⭐ | Desktop (empfohlen) |
| Llama 2 13B | 7.3 GB | 16 GB | ⭐⭐⭐⭐⭐ | High-End Workstations |
Retrieval-Augmented Generation = Dein LLM kann auf DEINE Daten zugreifen, nicht nur auf Training-Daten.
LLM: "Ich weiß nicht, welche Dateien du hast."
LLM: "Du hast 37 PDFs über Krypto im /finance Ordner, erstellt zwischen März-Juni 2024."
PDF, TXT, DOCX, Code → Text Chunks
Text → Vector (384/768 dimensions)
ChromaDB / FAISS / Pinecone
User Query → Top K relevante Chunks
Query + Retrieved Context → Answer
# Dependencies
pip install chromadb sentence-transformers pypdf langchain llama-index
import chromadb
from chromadb.config import Settings
from sentence_transformers import SentenceTransformer
# ChromaDB initialisieren (persistent)
client = chromadb.Client(Settings(
chroma_db_impl="duckdb+parquet",
persist_directory="./chroma_db"
))
# Collection erstellen
collection = client.get_or_create_collection(
name="os_documents",
metadata={"description": "All user documents and system files"}
)
# Embedding Model laden
embedder = SentenceTransformer('all-MiniLM-L6-v2')
def add_document(text, metadata):
"""Dokument zu Vector DB hinzufügen"""
# Text in Chunks aufteilen
chunks = split_text(text, chunk_size=500)
# Embeddings generieren
embeddings = embedder.encode(chunks)
# Zu DB hinzufügen
collection.add(
embeddings=embeddings.tolist(),
documents=chunks,
metadatas=[metadata] * len(chunks),
ids=[f"{metadata['file_id']}_{i}" for i in range(len(chunks))]
)
def split_text(text, chunk_size=500, overlap=50):
"""Text in überlappende Chunks aufteilen"""
words = text.split()
chunks = []
for i in range(0, len(words), chunk_size - overlap):
chunk = ' '.join(words[i:i + chunk_size])
chunks.append(chunk)
return chunks
from pypdf import PdfReader
import docx
import json
class DocumentProcessor:
def __init__(self, vector_store):
self.vector_store = vector_store
def process_file(self, filepath, file_id):
"""Automatisch Datei-Typ erkennen und verarbeiten"""
ext = filepath.split('.')[-1].lower()
if ext == 'pdf':
text = self.extract_pdf(filepath)
elif ext == 'txt':
text = self.extract_txt(filepath)
elif ext == 'docx':
text = self.extract_docx(filepath)
elif ext == 'json':
text = self.extract_json(filepath)
else:
return None
# Metadata
metadata = {
'file_id': file_id,
'filepath': filepath,
'type': ext,
'indexed_at': time.time()
}
# Zu Vector Store hinzufügen
add_document(text, metadata)
return True
def extract_pdf(self, filepath):
reader = PdfReader(filepath)
text = ""
for page in reader.pages:
text += page.extract_text()
return text
def extract_txt(self, filepath):
with open(filepath, 'r', encoding='utf-8') as f:
return f.read()
def extract_docx(self, filepath):
doc = docx.Document(filepath)
return '\n'.join([p.text for p in doc.paragraphs])
def extract_json(self, filepath):
with open(filepath, 'r') as f:
data = json.load(f)
return json.dumps(data, indent=2)
def rag_query(user_query, top_k=5):
"""Query mit RAG-Kontext"""
# 1. Query Embedding generieren
query_embedding = embedder.encode([user_query])[0]
# 2. Ähnliche Dokumente suchen
results = collection.query(
query_embeddings=[query_embedding.tolist()],
n_results=top_k
)
# 3. Kontext zusammenstellen
context = "\n\n".join(results['documents'][0])
# 4. Prompt für LLM bauen
prompt = f"""Basierend auf folgenden Informationen:
{context}
Beantworte die Frage: {user_query}
Antworte präzise und nutze nur die gegebenen Informationen.
"""
# 5. LLM aufrufen
response = llm(prompt)
return {
'answer': response,
'sources': results['metadatas'][0],
'context_used': context
}
# User: "Zeig mir alle Rechnungen von letztem Monat"
→ RAG findet: invoice_2024_01.pdf, invoice_2024_02.pdf
→ LLM antwortet: "Ich habe 2 Rechnungen gefunden: ..."
# User: "Fasse das Projekt-Meeting zusammen"
→ RAG findet: meeting_notes_2024_03_15.txt
→ LLM antwortet: "Im Meeting wurden folgende Punkte besprochen: ..."
# User: "Welche Python-Funktionen habe ich für API-Calls?"
→ RAG findet: api_utils.py, backend.py
→ LLM antwortet: "Du hast fetch_data(), post_request() in api_utils.py..."
Das LLM kann nicht nur antworten, sondern Aktionen ausführen.
User: "Erstelle eine Datei"
OS: "Befehl nicht erkannt"
User: "Erstelle eine Datei notes.txt"
LLM: Führt create_file('notes.txt') aus
OS: "✓ Datei erstellt"
Dateien, Ordner, Apps erstellen
Dateien lesen, durchsuchen, analysieren
Dateien bearbeiten, umbenennen
Dateien löschen, aufräumen
from langchain.tools import Tool
from langchain.agents import initialize_agent, AgentType
import os
import json
# CRUD Tools definieren
class FileSystemTools:
@staticmethod
def create_file(filename: str, content: str = "") -> str:
"""Erstellt eine neue Datei"""
try:
with open(f"./user_files/{filename}", 'w') as f:
f.write(content)
return f"✓ Datei {filename} erstellt"
except Exception as e:
return f"✗ Fehler: {str(e)}"
@staticmethod
def read_file(filename: str) -> str:
"""Liest eine Datei"""
try:
with open(f"./user_files/{filename}", 'r') as f:
return f.read()
except Exception as e:
return f"✗ Fehler: {str(e)}"
@staticmethod
def update_file(filename: str, content: str) -> str:
"""Aktualisiert eine Datei"""
try:
with open(f"./user_files/{filename}", 'w') as f:
f.write(content)
return f"✓ Datei {filename} aktualisiert"
except Exception as e:
return f"✗ Fehler: {str(e)}"
@staticmethod
def delete_file(filename: str) -> str:
"""Löscht eine Datei"""
try:
os.remove(f"./user_files/{filename}")
return f"✓ Datei {filename} gelöscht"
except Exception as e:
return f"✗ Fehler: {str(e)}"
@staticmethod
def list_files(directory: str = "./user_files") -> str:
"""Listet alle Dateien auf"""
try:
files = os.listdir(directory)
return json.dumps(files, indent=2)
except Exception as e:
return f"✗ Fehler: {str(e)}"
@staticmethod
def search_files(query: str) -> str:
"""Durchsucht Dateien nach Inhalt"""
results = []
for filename in os.listdir("./user_files"):
try:
with open(f"./user_files/{filename}", 'r') as f:
content = f.read()
if query.lower() in content.lower():
results.append(filename)
except:
continue
return json.dumps(results, indent=2)
from langchain.agents import initialize_agent, Tool, AgentType
# Tools definieren
tools = [
Tool(
name="CreateFile",
func=FileSystemTools.create_file,
description="Erstellt eine neue Datei. Input: filename, content"
),
Tool(
name="ReadFile",
func=FileSystemTools.read_file,
description="Liest den Inhalt einer Datei. Input: filename"
),
Tool(
name="UpdateFile",
func=FileSystemTools.update_file,
description="Aktualisiert eine bestehende Datei. Input: filename, content"
),
Tool(
name="DeleteFile",
func=FileSystemTools.delete_file,
description="Löscht eine Datei. Input: filename"
),
Tool(
name="ListFiles",
func=FileSystemTools.list_files,
description="Listet alle Dateien auf"
),
Tool(
name="SearchFiles",
func=FileSystemTools.search_files,
description="Durchsucht Dateien nach Text. Input: query"
)
]
# Agent initialisieren
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# Agent verwenden
response = agent.run("Erstelle eine Datei todo.txt mit Inhalt 'Projekt fertigstellen'")
print(response)
class SystemTools:
"""Erweiterte OS-Operationen"""
@staticmethod
def execute_shell(command: str) -> str:
"""Führt Shell-Befehle aus (SICHER!)"""
# Whitelist von erlaubten Befehlen
allowed = ['ls', 'pwd', 'date', 'whoami']
cmd = command.split()[0]
if cmd not in allowed:
return f"✗ Befehl '{cmd}' nicht erlaubt"
import subprocess
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=5
)
return result.stdout
except Exception as e:
return f"✗ Fehler: {str(e)}"
@staticmethod
def get_system_info() -> str:
"""Gibt System-Informationen zurück"""
import platform
info = {
'os': platform.system(),
'version': platform.version(),
'architecture': platform.machine(),
'processor': platform.processor()
}
return json.dumps(info, indent=2)
@staticmethod
def open_app(app_name: str) -> str:
"""Öffnet eine App"""
# Hier würdest du deine App-Launcher-Logik einbauen
return f"✓ App '{app_name}' geöffnet"
@staticmethod
def close_app(app_name: str) -> str:
"""Schließt eine App"""
return f"✓ App '{app_name}' geschlossen"
# Als Tools registrieren
system_tools = [
Tool(
name="ExecuteShell",
func=SystemTools.execute_shell,
description="Führt Shell-Befehle aus (nur sichere Befehle)"
),
Tool(
name="GetSystemInfo",
func=SystemTools.get_system_info,
description="Gibt System-Informationen zurück"
),
Tool(
name="OpenApp",
func=SystemTools.open_app,
description="Öffnet eine Anwendung. Input: app_name"
),
Tool(
name="CloseApp",
func=SystemTools.close_app,
description="Schließt eine Anwendung. Input: app_name"
)
]
👤 User: "Erstelle mir eine Shopping-Liste"
🤖 AI: [Ruft CreateFile('shopping.txt', '') auf]
✓ Datei shopping.txt erstellt
👤 User: "Füge Milch und Brot hinzu"
🤖 AI: [Ruft UpdateFile('shopping.txt', 'Milch\nBrot') auf]
✓ Datei shopping.txt aktualisiert
👤 User: "Was steht auf der Liste?"
🤖 AI: [Ruft ReadFile('shopping.txt') auf]
Auf deiner Shopping-Liste stehen:
- Milch
- Brot
👤 User: "Zeig mir alle Text-Dateien"
🤖 AI: [Ruft ListFiles() auf]
Ich habe folgende Dateien gefunden:
- shopping.txt
- notes.txt
- todo.txt
👤 User: "Durchsuche alle Dateien nach 'Projekt'"
🤖 AI: [Ruft SearchFiles('Projekt') auf]
'Projekt' wurde gefunden in:
- todo.txt
- notes.txt
┌─────────────────────────┐
│ Linux Kiosk Mode │
│ (Chromium Fullscreen) │
└────────┬────────────────┘
│
├─ Frontend (Browser)
│ └─ Web-OS UI
│
├─ Backend (localhost:8000)
│ ├─ Ollama (Mistral)
│ ├─ FastAPI Server
│ ├─ ChromaDB
│ └─ LangChain Agent
│
└─ File System
└─ /user_files/
┌─────────────────────────┐
│ Android WebView App │
└────────┬────────────────┘
│
├─ Frontend (WebView)
│ └─ Web-OS UI
│
├─ Backend (Remote/Cloud)
│ ├─ Ollama Server
│ ├─ REST API
│ └─ Vector DB
│
└─ Local Storage
└─ IndexedDB
# /etc/systemd/system/ai-os-backend.service
[Unit]
Description=AI OS Backend Server
After=network.target
[Service]
Type=simple
User=ai-user
WorkingDirectory=/home/ai-user/ai-os
ExecStart=/home/ai-user/ai-os-env/bin/uvicorn main:app --host 0.0.0.0 --port 8000
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
# Aktivieren
sudo systemctl enable ai-os-backend
sudo systemctl start ai-os-backend
# /etc/systemd/system/ollama.service
[Unit]
Description=Ollama LLM Server
After=network.target
[Service]
Type=simple
User=ai-user
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=10
Environment="OLLAMA_MODELS=/home/ai-user/.ollama/models"
[Install]
WantedBy=multi-user.target
# Aktivieren
sudo systemctl enable ollama
sudo systemctl start ollama
# ~/.config/autostart/ai-os-kiosk.desktop
[Desktop Entry]
Type=Application
Name=AI OS Kiosk
Exec=/usr/bin/chromium --kiosk --noerrdialogs --disable-infobars http://localhost:3000
X-GNOME-Autostart-enabled=true
X-GNOME-Autostart-Delay=10
# Für Geräte ohne GPU
export OLLAMA_NUM_GPU=0
ollama run mistral
# Für NVIDIA GPUs
export OLLAMA_NUM_GPU=1
ollama run mistral
| Konfiguration | CPU | RAM | Storage | LLM Model | Performance |
|---|---|---|---|---|---|
| Budget | 4 Cores | 8 GB | 32 GB SSD | TinyLlama | ⭐⭐ |
| Standard | 6-8 Cores | 16 GB | 128 GB SSD | Mistral 7B | ⭐⭐⭐⭐ |
| High-End | 8+ Cores | 32 GB | 256 GB NVMe | Llama 2 13B | ⭐⭐⭐⭐⭐ |
| Pro (+ GPU) | 8+ Cores | 32 GB | 512 GB NVMe | Llama 2 70B | ⭐⭐⭐⭐⭐ |
User: "Sortiere meine Dateien
nach Projekt"
AI: Analysiert alle Dateien
Erkennt Projekt-Bezüge
Erstellt Ordner
Verschiebt Dateien
✓ 47 Dateien sortiert
User: "Zeig mir alle Funktionen
mit Bugs"
AI: Durchsucht Code-Files
Analysiert mit RAG
Findet potenzielle Bugs
Schlägt Fixes vor
✓ 3 Probleme gefunden
User: "Was habe ich über
Kubernetes gelernt?"
AI: Durchsucht Notizen
Extrahiert mit RAG
Fasst zusammen
Verlinkt Quellen
✓ Zusammenfassung bereit
Keine Cloud, keine API-Keys, keine Limits
RAG kennt alle deine Dateien und Apps
CRUD-Skills führen echte OS-Operationen aus